package main

import (
    "fmt"
    "github.com/vishvananda/netlink"
    "os/exec"
    )

func main() {
    // 毁坏测试
    fmt.Println("\n 包毁坏测试")
    NetCorruption(20)
    check_interface_status()
    StopNetCorruption()
    check_interface_status()

}

// 检查状态
func check_interface_status() {
    output, err := exec.Command("/sbin/tc", "qdisc").Output()
    if err != nil {
        fmt.Println("error in cmd.start()")
    }
    fmt.Printf("%v", string(output))
}

// 获得网卡的 Index
func get_interface_list() []int {
    interfaces, _ := netlink.LinkList()
    var interface_index []int
    for _, name := range interfaces[1:] {
        interface_index = append(interface_index, name.Attrs().Index)
    }
    return interface_index
}

// 构造出每网卡 qdisc 属性, 类似 dev inferface_name root netem
func constructor_qdiscattrs() []netlink.QdiscAttrs {
    linkindexs := get_interface_list()
    var netems []netlink.QdiscAttrs
    for _, indexs := range linkindexs {
        var qdisc_attrs = netlink.QdiscAttrs{
            Parent:    netlink.HANDLE_ROOT,
            LinkIndex: indexs,
        }
        netems = append(netems, qdisc_attrs)
    }
    return netems
}

// 具体的 do 执行
func traffic_control(nattrs netlink.NetemQdiscAttrs) error {
    var netems = constructor_qdiscattrs()
    for _, netem := range netems {
        err := netlink.QdiscAdd(netlink.NewNetem(netem, nattrs))
        if err != nil {
            fmt.Printf("traffic_control %v \n", err)
            return err
        }
    }
    return nil
}

// 具体的 undo 执行
func undo_traffic_control() error {
    fmt.Println("undo operation")
    links, _ := netlink.LinkList()
    for _, link := range links {
        netems, _ := netlink.QdiscList(link)
        for _, netem := range netems {
            err := netlink.QdiscDel(netem)
            if err != nil {
                fmt.Printf("undo_traffic_control %v \n", err)
                return err
            }
        }
    }
    return nil
}

// 实参单位是 %, 例如实参是 80, 表示损坏率 80%
func NetCorruption(precents float32) {
    var nattrs netlink.NetemQdiscAttrs
    nattrs.CorruptProb = precents
    traffic_control(nattrs)
}

func StopNetCorruption() {
    undo_traffic_control()
}
0x21 monitor routing table
当然可以直接使用系统自带的rtnetlink.h来监控路由表.

#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <arpa/inet.h>
#include <unistd.h>

#define ERR_RET(x) do { perror(x); return EXIT_FAILURE; } while (0);
#define BUFFER_SIZE 4095

int  loop (int sock, struct sockaddr_nl *addr)
{
    int     received_bytes = 0;
    struct  nlmsghdr *nlh;
    char    destination_address[32];
    char    gateway_address[32];
    struct  rtmsg *route_entry;  /* This struct represent a route entry in the routing table */
    struct  rtattr *route_attribute; /* This struct contain route attributes (route type) */
    int     route_attribute_len = 0;
    char    buffer[BUFFER_SIZE];
    
    bzero(destination_address, sizeof(destination_address));
    bzero(gateway_address, sizeof(gateway_address));
    bzero(buffer, sizeof(buffer));

    /* Receiving netlink socket data */
    while (1) {
        received_bytes = recv(sock, buffer, sizeof(buffer), 0);
        if (received_bytes < 0)
            ERR_RET("recv");
        /* cast the received buffer */
            nlh = (struct nlmsghdr *) buffer;
        /* If we received all data ---> break */
        if (nlh->nlmsg_type == NLMSG_DONE)
            break;
        /* We are just intrested in Routing information */
        if (addr->nl_groups == RTMGRP_IPV4_ROUTE)
            break;
        }

/* Reading netlink socket data */
/* Loop through all entries */
/* For more informations on some functions :
 * http://www.kernel.org/doc/man-pages/online/pages/man3/netlink.3.html
 * http://www.kernel.org/doc/man-pages/online/pages/man7/rtnetlink.7.html
 */

for ( ; NLMSG_OK(nlh, received_bytes); nlh = NLMSG_NEXT(nlh, received_bytes))
{
    /* Get the route data */
    route_entry = (struct rtmsg *) NLMSG_DATA(nlh);

    /* We are just intrested in main routing table */
    if (route_entry->rtm_table != RT_TABLE_MAIN)
        continue;

    /* Get attributes of route_entry */
    route_attribute = (struct rtattr *) RTM_RTA(route_entry);

    /* Get the route atttibutes len */
    route_attribute_len = RTM_PAYLOAD(nlh);
    
    /* Loop through all attributes */
    for ( ; RTA_OK(route_attribute, route_attribute_len); route_attribute = RTA_NEXT(route_attribute, route_attribute_len))
    {
        /* Get the destination address */
        if (route_attribute->rta_type == RTA_DST)
        {
            inet_ntop(AF_INET, RTA_DATA(route_attribute), destination_address, sizeof(destination_address));
        }
        /* Get the gateway (Next hop) */
        if (route_attribute->rta_type == RTA_GATEWAY)
        {
            inet_ntop(AF_INET, RTA_DATA(route_attribute), gateway_address, sizeof(gateway_address));
        }
    }

    /* Now we can dump the routing attributes */
    if (nlh->nlmsg_type == RTM_DELROUTE)
        fprintf(stdout, "Deleting route to destination --> %s and gateway %s\n", destination_address, gateway_address);
    if (nlh->nlmsg_type == RTM_NEWROUTE)
        printf("Adding route to destination --> %s and gateway %s\n", destination_address, gateway_address);
}
    return 0;
}

int main(int argc, char **argv)
{
    int sock = -1;
    struct sockaddr_nl addr;

    /* Zeroing addr */
    bzero (&addr, sizeof(addr));
    
    if ((sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0)
        ERR_RET("socket");

    addr.nl_family = AF_NETLINK;
    addr.nl_groups = RTMGRP_IPV4_ROUTE;
    
    if (bind(sock,(struct sockaddr *)&addr,sizeof(addr)) < 0)
        ERR_RET("bind");
        
    while (1)
        loop (sock, &addr);
        
    /* Close socket */
    close(sock);
    return 0;
}